home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 351-375 / 351 / pdc / pdcsrc.lzh / PDC / GetSym.c < prev    next >
C/C++ Source or Header  |  1990-04-06  |  24KB  |  1,044 lines

  1.  
  2. /* PDC Compiler - A Freely Distributable C Compiler for the Amiga
  3.  *                Based upon prior work by Matthew Brandt and Jeff Lydiatt.
  4.  *
  5.  * PDC Compiler release 3.3 Copyright (C) 1989 Paul Petersen and Lionel Hummel.
  6.  * PDC Software Distribution (C) 1989 Lionel Hummel and Paul Petersen.
  7.  *
  8.  * This code is freely redistributable upon the conditions that this 
  9.  * notice remains intact and that modified versions of this file not be 
  10.  * distributed as part of the PDC Software Distribution without the express
  11.  * consent of the copyright holders.
  12.  *
  13.  *------------------------------------------------------------------
  14.  *
  15.  * $Log:    GetSym.c,v $
  16.  * Revision 3.33  90/04/05  22:34:48  lionel
  17.  * None.
  18.  * 
  19.  * Revision 3.32  90/02/03  16:24:30  lionel
  20.  * None
  21.  * 
  22.  *------------------------------------------------------------------
  23.  */
  24.  
  25. /*
  26.  * GetSym.c
  27.  * 
  28.  * A hodgepodge of routines for advanced input, error handling, and init's.
  29.  * Oh yeah, it also contains the lexical analyzer.
  30.  */
  31.  
  32. #include    <stdio.h>
  33. #include    <ctype.h>
  34. #include    <assert.h>
  35.  
  36. #ifndef unix
  37. #define GENERATE_TIME
  38. #endif
  39.  
  40. #ifdef AZTEC_C
  41. #define isidch(x)    ((ctp_[(x)+1] & 0x07) || ((x) == '_') || ((x) == '$'))
  42. #include    <time.h>
  43.  
  44. #else
  45. #ifdef GENERATE_TIME
  46. #include    <sys/time.h>
  47. #endif
  48. #endif
  49.  
  50. #include    "C.h"
  51. #include    "Expr.h"
  52. #include    "Gen.h"
  53. #include    "Cglbdec.h"
  54.  
  55. #define LINDEPTH    20
  56.  
  57. static char    *months[] = {
  58.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  59.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  60. };
  61.  
  62. extern char    *itoa();
  63. extern SYM     *search();
  64. extern char    *prepdefine();
  65. extern char    *litlate();
  66. extern char    *fgets();
  67.  
  68. extern TABLE             tagtable;
  69. extern unsigned char    *lptr;           /* shared with preproc */
  70. extern FILE             *inclfile[10];   /* shared with preproc */
  71. extern int               inclline[10];   /* shared with preproc */
  72. extern char             *inclname[10];   /* shared with preproc */
  73.  
  74. extern int      incldepth;  /* shared with preproc */
  75. extern int      inpreproc;  /* shared with preproc */
  76. extern int      oneline;    /* shared with preproc */
  77. extern enum e_pm premode;   /* shared with preproc */
  78. extern enum e_ps prestat;   /* shared with preproc */
  79.  
  80. extern char     __linebuf[];
  81. extern char     __filebuf[];
  82. extern char     __datebuf[];
  83. extern char     __funcbuf[];
  84. extern char     __timebuf[];
  85.  
  86. #define MAX_ERRORS  80
  87.  
  88. int             fatal = FALSE;
  89. static int      errno[MAX_ERRORS];
  90. static char    *errxx[MAX_ERRORS];
  91.  
  92. static int      numerrs;
  93. char            in_line[1024];
  94. int             in_line_used;
  95. int             in_comment = FALSE;
  96. int             total_errors = 0;
  97. int             join_line = FALSE;
  98. int             lstackptr = 0;  /* substitution stack pointer   */
  99. int             dbxlnum = 0;    /* Line number for DBX      */
  100. unsigned char  *linstack[LINDEPTH]; /* stack for substitutions      */
  101. unsigned char   chstack[LINDEPTH];  /* place to save lastch     */
  102.  
  103. #define MAXERR  29
  104.  
  105. static char    *errmsg[] =
  106. {
  107.     "Syntax",
  108.     "Bad Character",
  109.     "Floating Point Error",
  110.     "Bad Type",
  111.     "Undefined Symbol",
  112.     "Duplicate Symbol",
  113.     "Punctuation",
  114.     "Identifier expected",
  115.     "Not initialized",
  116.     "Incomplete",
  117.     "Bad initialization",
  118.     "Init size",
  119.     "Bad Class statement",
  120.     "Bad Block",
  121.     "No Pointer",
  122.     "No Function",
  123.     "No Member",
  124.     "L-Value expected",
  125.     "Dereferencing error",
  126.     "Mismatch",
  127.     "Expression expected",
  128.     "While expected",
  129.     "No case",
  130.     "Duplicate case",
  131.     "Label error",
  132.     "Preprocessor error",
  133.     "Include file error",
  134.     "Can't open include file",
  135.     "Define error",
  136.     "Prototype mismatch",
  137. };
  138.  
  139. #ifdef GENERATE_TIME
  140.  
  141. void
  142. time_and_date()
  143. {
  144.     struct tm       *tp;
  145.     long            timeval;
  146.  
  147.     time( &timeval );
  148.     tp = localtime( &timeval );
  149.  
  150.     strcpy( __datebuf, "\"" );
  151.     strcat( __datebuf, months[ tp->tm_mon ]);
  152.     strcat( __datebuf, " " );
  153.     strcat( __datebuf, itoa(tp->tm_mday));
  154.     strcat( __datebuf, " 19" );
  155.     strcat( __datebuf, itoa(tp->tm_year));
  156.     strcat( __datebuf, "\"" );
  157.  
  158.     strcpy( __timebuf, "\"" );
  159.  
  160.     if (tp->tm_hour < 10)
  161.         strcat( __timebuf, "0" );
  162.     strcat( __timebuf, itoa(tp->tm_hour));
  163.  
  164.     if (tp->tm_min < 10)
  165.         strcat( __timebuf, ":0" );
  166.     else
  167.         strcat( __timebuf, ":" );
  168.  
  169.     strcat( __timebuf, itoa(tp->tm_min));
  170.  
  171.     if (tp->tm_sec < 10)
  172.         strcat( __timebuf, ":0" );
  173.     else
  174.         strcat( __timebuf, ":" );
  175.  
  176.     strcat( __timebuf, itoa(tp->tm_sec));
  177.  
  178.     strcat( __timebuf, "\"" );
  179. }
  180.  
  181. #endif
  182.  
  183. void
  184. install_defines()
  185. {
  186.     SYM *sp;
  187.  
  188.     strcpy(__linebuf, itoa(dbxlnum));
  189.     padstr(__filebuf, curfile);
  190.  
  191.     padstr(__funcbuf, "**PDC**");
  192.  
  193. #ifdef GENERATE_TIME
  194.     time_and_date();
  195. #endif
  196.  
  197.     setdefine("__LINE__", __linebuf);
  198.     setdefine("__FILE__", __filebuf);
  199.     setdefine("__DATE__", __datebuf);
  200.     setdefine("__TIME__", __timebuf);
  201.     setdefine("__FUNC__", __funcbuf);
  202.     setdefine("__PDC__", " 1 ");
  203.     setdefine("pdc", " 1 ");
  204.     setdefine("amiga", " 1 ");
  205. #ifdef unix
  206.     setdefine("unix", " 1 ");
  207. #endif
  208.  
  209.     if (Options.Builtin) {
  210.         setdefine("strcmp", "__BUILTIN_strcmp");
  211.         setdefine("strcpy", "__BUILTIN_strcpy");
  212.         setdefine("strlen", "__BUILTIN_strlen");
  213.         setdefine("strcat", "__BUILTIN_strcat");
  214.         setdefine("bcopy", "__BUILTIN_bcopy");
  215.         setdefine("bzero", "__BUILTIN_bzero");
  216.     }
  217.     for (sp = cmd_defsyms.head; sp != NULL; sp = sp->next) {
  218.         if (search(sp->name, defsyms.head) != NULL) 
  219.             remove( sp->name, &defsyms );
  220.         if (sp->value.s != NULL)
  221.             setdefine( sp->name, sp->value.s );
  222.         else
  223.             setdefine( sp->name, " 1 " );
  224.     }
  225.     for (sp = cmd_undefsyms.head; sp != NULL; sp = sp->next) 
  226.         remove( sp->name, &defsyms );
  227. }
  228.  
  229. void
  230. initsym()
  231. {
  232.     defsyms.head = defsyms.tail = NULL;
  233.     tagtable.head = tagtable.tail = NULL;
  234.     lsyms.head = lsyms.tail = NULL;
  235.     gsyms.head = gsyms.tail = NULL;
  236.     cmd_local.head = cmd_local.tail = NULL;
  237.  
  238.     in_line[0] = '\0';
  239.     lptr = (unsigned char *) in_line;
  240.     nextlabel = 1;
  241.     numerrs = 0;
  242.     total_errors = 0;
  243.     lineno = 0;
  244.     dbxlnum = 0;
  245.     fatal = FALSE;
  246.     libpragma = NULL;
  247. }
  248.  
  249. int
  250. getline(listflag)
  251.     int             listflag;
  252. {
  253.     int             err, i;
  254.     char            rv, *s, *data;
  255.  
  256.     do {
  257.         if (Options.List && listflag && lineno > 0) {
  258.             fprintf(list, "%-6d\t%s", lineno, in_line);
  259.         }
  260.  
  261.         if (numerrs) {
  262.  
  263.             /*
  264.              * Print where any error(s) was (were) found:
  265.              */
  266.             if (!(Options.List && listflag)) {
  267.                 if (numerrs == 1)
  268.                     fprintf( stderr, "\nError in " );
  269.                 else
  270.                     fprintf( stderr, "\nErrors in " );
  271.                 if (lineno > 0) {
  272.                     fprintf(stderr, "line %d of ", lineno);
  273.                 }
  274.                 fprintf(stderr, "%s:\n%s", curfile, in_line);
  275.             }
  276.  
  277.             /*
  278.              * Describe the errors:
  279.              */
  280.             for (i = 0; numerrs--; ++i) {
  281.                 err = errno[i];
  282.                 s = (char *) " *** error ";
  283.                 fprintf(stderr, "%s%d", s, err);
  284.                 if (err <= MAXERR) {
  285.                     fprintf(stderr, " %s", errmsg[err]);
  286.                     if (errxx[i] != NULL) {
  287.                         fprintf(stderr, " : %s", errxx[i]);
  288.                     }
  289.                 }
  290.                 else {
  291.                     if (Options.List && listflag && lineno > 0) {
  292.                         fprintf(list, "%s%d\n", s, err);
  293.                         if (errxx[i] != NULL) {
  294.                             fprintf(list, " : %s", errxx[i]);
  295.                         }
  296.                         fprintf( list, "\n" );
  297.                     }
  298.                 }
  299.                 fprintf( stderr, "\n" );
  300.             }
  301.         }
  302.  
  303.         numerrs = 0;
  304.         ++lineno;
  305.  
  306.         data = fgets(in_line, sizeof(in_line) - 1, input);
  307.  
  308.         in_line_used = 0;
  309.         rv = feof(input);
  310.         if (data == NULL && rv && incldepth > 0) {
  311.             fclose(input);
  312.             input = inclfile[--incldepth];
  313.             lineno = dbxlnum = inclline[incldepth];
  314.             curfile = inclname[incldepth];
  315.             padstr( __filebuf, curfile );
  316.             strcpy( __linebuf, itoa(dbxlnum));
  317.             return getline(0);
  318.         }
  319.  
  320.         if (data == NULL && rv)
  321.             return 1;
  322.  
  323.         ++dbxlnum;
  324.         strcpy(__linebuf, itoa(dbxlnum));
  325.  
  326.         lptr = (unsigned char *) in_line;
  327.         if (in_line[0] == '#' && !in_comment)
  328.             return preprocess();
  329.     } while (prestat == ps_ignore);
  330.     return 0;
  331. }
  332.  
  333. /*
  334.  * getch - basic get character routine.
  335.  */
  336.  
  337. int
  338. getch()
  339. {
  340.     while ((lastch = *lptr++) == '\0') {
  341.         if (lstackptr > 0) {
  342.             lptr = linstack[--lstackptr];
  343.             lastch = chstack[lstackptr];
  344.             return lastch;
  345.         }
  346.         if (oneline)
  347.             return lastch = -1;
  348.         if (getline(incldepth == 0))
  349.             return lastch = -1;
  350.     }
  351.     return lastch;
  352. }
  353.  
  354. /*
  355.  * joinch - basic get character routine, will NOT obey oneline.
  356.  */
  357.  
  358. int
  359. joinch()
  360. {
  361.     while ((lastch = *lptr++) == '\0') {
  362.         if (lstackptr > 0) {
  363.             lptr = linstack[--lstackptr];
  364.             lastch = chstack[lstackptr];
  365.             return lastch;
  366.         }
  367.         if (getline(incldepth == 0))
  368.             return lastch = -1;
  369.     }
  370.     return lastch;
  371. }
  372.  
  373. /*
  374.  * error - print error information
  375.  */
  376.  
  377. void
  378. fatal_error(n, msg)
  379.     int             n;
  380.     char           *msg;
  381. {
  382.     fatal = TRUE;
  383.  
  384.     if (numerrs < MAX_ERRORS) {
  385.         errno[numerrs] = n;
  386.         errxx[numerrs] = msg;
  387.         ++numerrs;
  388.         ++total_errors;
  389.     }
  390. }
  391.  
  392. void
  393. error(n, msg)
  394.     int             n;
  395.     char           *msg;
  396. {
  397.     if (numerrs < MAX_ERRORS) {
  398.         errno[numerrs] = n;
  399.         errxx[numerrs] = msg;
  400.         ++numerrs;
  401.         ++total_errors;
  402.     }
  403. }
  404.  
  405. #ifndef isidch
  406. int
  407. isidch( x )
  408.     int x;
  409. {
  410.     return(x == '$' || x == '_' || isalpha(x) || isdigit(x));
  411. }
  412. #endif
  413.  
  414. /*
  415.  * getid - get an identifier.
  416.  * 
  417.  * identifiers are any isidch conglomerate that doesn't start with a numeric
  418.  * character. this set INCLUDES keywords.
  419.  */
  420.  
  421. void 
  422. getid()
  423. {
  424.     int             i = 0;
  425.  
  426.     lastst = id;
  427.     while (isidch(lastch)) {
  428.         if (i < MAX_ID)
  429.             lastid[i++] = lastch;
  430.         getch();
  431.     }
  432.     lastid[i] = '\0';
  433. }
  434.  
  435. int
  436. gethex_ch()
  437. {
  438.     int     j, v = 0;
  439.  
  440.     for (j = 0; j < 2; ++j) {
  441.         if (lastch <= '9' && lastch >= '0')
  442.             v = (v << 4) + lastch - '0';
  443.         else if (lastch <= 'f' && lastch >= 'a')
  444.             v = (v << 4) + lastch - 'a' + 10;
  445.         else if (lastch <= 'F' && lastch >= 'A')
  446.             v = (v << 4) + lastch - 'A' + 10;
  447.         else
  448.             break;
  449.         getch();
  450.     }
  451.     return (v);
  452. }
  453.  
  454. int
  455. getoct_ch()
  456. {
  457.     int     j, v = 0;
  458.  
  459.     for (j = 0; j < 3; ++j) {
  460.         if (lastch == 'x' && v == 0) {
  461.             getch();
  462.             return( gethex_ch() );
  463.         }
  464.         if (lastch > '7' || lastch < '0')
  465.             break;
  466.         v = (v << 3) + lastch - '0';
  467.         getch();
  468.     }
  469.     return( v );
  470. }
  471.  
  472. /*
  473.  * getsch - get a character in a quoted string.
  474.  * 
  475.  * this routine handles all of the escape mechanisms for characters in strings
  476.  * and character constants.
  477.  */
  478. int
  479. getsch()
  480. {               /* return an in-quote character */
  481.     register int    i, j;
  482.  
  483.     if (lastch == '\n')
  484.         return -1;
  485.     if (lastch != '\\') {
  486.         i = lastch;
  487.         getch();
  488.         return i;
  489.     }
  490.  
  491.     getch();        /* get an escaped character */
  492.  
  493.     if (lastch == 'x' || isdigit(lastch)) 
  494.         return( getoct_ch() );
  495.  
  496.     i = lastch;
  497.     getch();
  498.     if (i == '\n')
  499.         return getsch();
  500.  
  501.     switch (i) {
  502.     case 'a':
  503.         return '\a';
  504.     case 'b':
  505.         return '\b';
  506.     case 'f':
  507.         return '\f';
  508.     case 'n':
  509.         return '\n';
  510.     case 'r':
  511.         return '\r';
  512.     case 't':
  513.         return '\t';
  514.     case 'v':
  515.         return '\v';
  516.     default:
  517.         return i;
  518.     }
  519. }
  520.  
  521. int
  522. radix36(c)
  523.     char            c;
  524. {
  525.     if (isdigit(c))
  526.         return c - '0';
  527.     if (c >= 'a' && c <= 'z')
  528.         return c - 'a' + 10;
  529.     if (c >= 'A' && c <= 'Z')
  530.         return c - 'A' + 10;
  531.     return -1;
  532. }
  533.  
  534. /*
  535.  * getbase - get an integer in any base.
  536.  */
  537.  
  538. void
  539. getbase(b)
  540.     char            b;
  541. {
  542.     register long   i, j;
  543.  
  544.     i = 0;
  545.     while (isalnum(lastch)) {
  546.         if ((j = radix36(lastch)) < b) {
  547.             i = i * b + j;
  548.             getch();
  549.         }
  550.         else
  551.             break;
  552.     }
  553.     ival = i;
  554.     lastst = iconst;
  555. }
  556.  
  557. /*
  558.  * getfrac - get fraction part of a floating number.
  559.  */
  560.  
  561. void
  562. getfrac()
  563. {
  564.     double          frmul;
  565.  
  566.     frmul = 0.1;
  567.     while (isdigit(lastch)) {
  568.         rval += frmul * (lastch - '0');
  569.         getch();
  570.         frmul *= 0.1;
  571.     }
  572. }
  573.  
  574. /*
  575.  * getexp - get exponent part of floating number.
  576.  * 
  577.  * this algorithm is primative but usefull.  Floating exponents are limited to
  578.  * +/-255 but most hardware won't support more anyway.
  579.  */
  580.  
  581. void
  582. getexp()
  583. {
  584.     int             nexp = 0;
  585.  
  586.     if (lastst != rconst)
  587.         rval = ival;
  588.     if (lastch == '+' || lastch == '-') {
  589.         nexp = (lastch == '-');
  590.         getch();
  591.     }
  592.     getbase(10);
  593.  
  594.     if (ival > 310)
  595.         error(ERR_FPCON, NULL);
  596.     else {
  597.         if (nexp) {
  598.             while (ival-- > 0)
  599.                 rval *= 0.1;
  600.         }
  601.         else {
  602.             while (ival-- > 0)
  603.                 rval *= 10.0;
  604.         }
  605.     }
  606.     lastst = rconst;
  607. }
  608.  
  609. /*
  610.  * getnumber - get a number from input.
  611.  * 
  612.  * getnumber handles all of the numeric input. it accepts decimal, octal,
  613.  * hexidecimal, and floating point numbers.
  614.  */
  615.  
  616. void
  617. getnumber()
  618. {
  619.     if (lastch != '0')
  620.         getbase(10);
  621.     else {
  622.         getch();
  623.         if (lastch == 'x' || lastch == 'X') {
  624.             getch();
  625.             getbase(16);
  626.         }
  627.         else if (lastch == '.')
  628.             ival = 0;
  629.         else
  630.             getbase(8);
  631.     }
  632.  
  633.     if (lastch == '.') {
  634.         getch();
  635.         rval = ival;    /* float the integer part */
  636.         getfrac();  /* add the fractional part */
  637.         lastst = rconst;
  638.     }
  639.     if (lastch == 'e' || lastch == 'E') {
  640.         getch();
  641.         getexp();   /* get the exponent */
  642.     }
  643.  
  644.     if (lastst == iconst && (lastch == 'l' || lastch == 'L')) {
  645.         lastst = iconst;
  646.         getch();
  647.     }
  648. }
  649.  
  650. void
  651. getdotnumber()
  652. {
  653.     rval = 0.0;     /* float the integer part */
  654.     getfrac();      /* add the fractional part */
  655.     lastst = rconst;
  656.  
  657.     if (lastch == 'e' || lastch == 'E') {
  658.         getch();
  659.         getexp();   /* get the exponent */
  660.     }
  661. }
  662.  
  663. static char *
  664. charmsg( ch )
  665.     int ch;
  666. {
  667.     char    *ptr, buffer[80];
  668.  
  669.     strcpy( buffer, "unknown character (" );
  670.     strcat( buffer, itoa(ch));
  671.  
  672.     for (ptr = buffer; *ptr; ++ptr);
  673.  
  674.     *ptr++ = ')';
  675.     *ptr++ = ' ';
  676.     *ptr++ = '\'';
  677.  
  678.     if (ch >= 32)
  679.         *ptr++ = ch;
  680.     else {
  681.         *ptr++ = '^';
  682.         *ptr++ = (ch + '@');
  683.     }
  684.     *ptr++ = '\'';
  685.     *ptr = '\0';
  686.     return( litlate(buffer) );
  687. }
  688.  
  689. /*
  690.  * getsym - get next symbol from input stream.
  691.  * 
  692.  * getsym is the basic lexical analyzer.  It builds basic tokens out of the
  693.  * characters on the input stream and sets the following global variables:
  694.  * 
  695.  *  lastch:    A look behind buffer. 
  696.  *  lastst:    type of last symbol read.
  697.  *  laststr:   last string constant read. 
  698.  *  lastid:    last identifier read. 
  699.  *  ival:      last integer constant read. 
  700.  *  rval:      last real constant read.
  701.  * 
  702.  * getsym should be called for all your input needs...
  703.  */
  704.  
  705. void
  706. getsym()
  707. {
  708.     register int    i, j;
  709.     unsigned char  *loc;
  710.     SYM            *sp;
  711.  
  712. restart:            /* we come back here after comments */
  713.  
  714.     while (premode != pr_asm && isspace(lastch))
  715.         getch();
  716.  
  717.     if (premode == pr_asm && !oneline) {
  718.         if (lastch == -1) {
  719.             lastst = eof;
  720.             return;
  721.         }
  722.         for (i = 0; i < MAX_STRLEN; ++i) {
  723.             if (lastch == '\n' || lastch == -1 || (j = getsch()) == -1)
  724.                 break;
  725.             laststr[i] = j;
  726.         }
  727.         laststr[i] = 0;
  728.         if (lastch == '\n')
  729.             getch();
  730.         else
  731.             error(ERR_SYNTAX, NULL);
  732.         lastst = asmconst;
  733.         return;
  734.     }
  735.  
  736.     while (isspace(lastch))
  737.         getch();
  738.  
  739.     if (lastch == -1)
  740.         lastst = eof;
  741.     else if (isdigit(lastch))
  742.         getnumber();
  743.     else if (isidch(lastch)) {
  744.         getid();
  745.         if (!inpreproc && (sp = search(lastid, defsyms.head)) != NULL) {
  746.             loc = (unsigned char *) prepdefine(sp);
  747.             if (loc != NULL) {
  748.                 if (lstackptr >= LINDEPTH) {
  749.                     error(ERR_DEFINE, NULL);
  750.                     lstackptr = 0;
  751.                     lptr = linstack[lstackptr];
  752.                     lastch = chstack[lstackptr];
  753.                 }
  754.                 else {
  755.                     linstack[lstackptr] = lptr;
  756.                     chstack[lstackptr++] = lastch;
  757.                     lptr = loc;
  758.                     getch();
  759.                     goto restart;
  760.                 }
  761.             }
  762.         }
  763.     }
  764.     else
  765.         switch (lastch) {
  766.         case '+':
  767.             getch();
  768.             if (lastch == '+') {
  769.                 getch();
  770.                 lastst = autoinc;
  771.             }
  772.             else if (lastch == '=') {
  773.                 getch();
  774.                 lastst = asplus;
  775.             }
  776.             else
  777.                 lastst = plus;
  778.             break;
  779.         case '-':
  780.             getch();
  781.             if (lastch == '-') {
  782.                 getch();
  783.                 lastst = autodec;
  784.             }
  785.             else if (lastch == '=') {
  786.                 getch();
  787.                 lastst = asminus;
  788.             }
  789.             else if (lastch == '>') {
  790.                 getch();
  791.                 lastst = pointsto;
  792.             }
  793.             else
  794.                 lastst = minus;
  795.             break;
  796.         case '*':
  797.             getch();
  798.             if (lastch == '=') {
  799.                 getch();
  800.                 lastst = astimes;
  801.             }
  802.             else
  803.                 lastst = star;
  804.             break;
  805.         case '/':
  806.             getch();
  807.             if (lastch == '=') {
  808.                 getch();
  809.                 lastst = asdivide;
  810.             }
  811.             else if (lastch == '*') {
  812.                 in_comment = TRUE;
  813.                 getch();
  814.                 for (;;) {
  815.                     if (lastch == '*') {
  816.                         getch();
  817.                         if (lastch == '/') {
  818.                             getch();
  819.                             in_comment = FALSE;
  820.                             goto restart;
  821.                         }
  822.                     }
  823.                     else
  824.                         getch();
  825.                 }
  826.             }
  827.             else
  828.                 lastst = divide;
  829.             break;
  830.         case '^':
  831.             getch();
  832.             if (lastch == '=') {
  833.                 getch();
  834.                 lastst = aseor;
  835.             }
  836.             else
  837.                 lastst = uparrow;
  838.             break;
  839.         case ';':
  840.             getch();
  841.             lastst = semicolon;
  842.             break;
  843.         case ':':
  844.             getch();
  845.             lastst = colon;
  846.             break;
  847.         case '=':
  848.             getch();
  849.             if (lastch == '=') {
  850.                 getch();
  851.                 lastst = eq;
  852.             }
  853.             else
  854.                 lastst = assign;
  855.             break;
  856.         case '>':
  857.             getch();
  858.             if (lastch == '=') {
  859.                 getch();
  860.                 lastst = geq;
  861.             }
  862.             else if (lastch == '>') {
  863.                 getch();
  864.                 if (lastch == '=') {
  865.                     getch();
  866.                     lastst = asrshift;
  867.                 }
  868.                 else
  869.                     lastst = rshift;
  870.             }
  871.             else
  872.                 lastst = gt;
  873.             break;
  874.         case '<':
  875.             getch();
  876.             if (lastch == '=') {
  877.                 getch();
  878.                 lastst = leq;
  879.             }
  880.             else if (lastch == '<') {
  881.                 getch();
  882.                 if (lastch == '=') {
  883.                     getch();
  884.                     lastst = aslshift;
  885.                 }
  886.                 else
  887.                     lastst = lshift;
  888.             }
  889.             else
  890.                 lastst = lt;
  891.             break;
  892.         case '\'':
  893.             getch();
  894.             ival = getsch();    /* get a string char */
  895.             if (lastch != '\'')
  896.                 error(ERR_SYNTAX, NULL);
  897.             else
  898.                 getch();
  899.             lastst = cconst;
  900.             break;
  901.         case '\"':
  902.             getch();
  903.             i = 0;
  904.             for (;;) {
  905.                 if (lastch == '\"')
  906.                     break;
  907.                 if ((j = getsch()) == -1)
  908.                     break;
  909.                 if (i < MAX_STRLEN) 
  910.                     laststr[i++] = j;
  911.             }
  912.             laststr[i] = 0;
  913.             lastst = sconst;
  914.             if (lastch != '\"')
  915.                 error(ERR_SYNTAX, NULL);
  916.             else
  917.                 getch();
  918.             break;
  919.         case '!':
  920.             getch();
  921.             if (lastch == '=') {
  922.                 getch();
  923.                 lastst = neq;
  924.             }
  925.             else
  926.                 lastst = not;
  927.             break;
  928.         case '%':
  929.             getch();
  930.             if (lastch == '=') {
  931.                 getch();
  932.                 lastst = asmodop;
  933.             }
  934.             else
  935.                 lastst = modop;
  936.             break;
  937.         case '~':
  938.             getch();
  939.             lastst = compl;
  940.             break;
  941.         case '.':
  942.             getch();
  943.             if (isdigit(lastch)) {
  944.                 getdotnumber();
  945.             }
  946.             else if (lastch != '.')
  947.                 lastst = dot;
  948.             else {
  949.                 getch();
  950.                 if (lastch == '.') {
  951.                     getch();
  952.                     lastst = ellipsis;
  953.                 }
  954.                 else {
  955.                     error(ERR_ILLCHAR, charmsg( lastch ) );
  956.                     goto restart;   /* get a real token */
  957.                 }
  958.             }
  959.             break;
  960.         case ',':
  961.             getch();
  962.             lastst = comma;
  963.             break;
  964.         case '&':
  965.             getch();
  966.             if (lastch == '&') {
  967.                 lastst = land;
  968.                 getch();
  969.             }
  970.             else if (lastch == '=') {
  971.                 lastst = asand;
  972.                 getch();
  973.             }
  974.             else
  975.                 lastst = and;
  976.             break;
  977.         case '|':
  978.             getch();
  979.             if (lastch == '|') {
  980.                 lastst = lor;
  981.                 getch();
  982.             }
  983.             else if (lastch == '=') {
  984.                 lastst = asor;
  985.                 getch();
  986.             }
  987.             else
  988.                 lastst = or;
  989.             break;
  990.         case '(':
  991.             getch();
  992.             lastst = openpa;
  993.             break;
  994.         case ')':
  995.             getch();
  996.             lastst = closepa;
  997.             break;
  998.         case '[':
  999.             getch();
  1000.             lastst = openbr;
  1001.             break;
  1002.         case ']':
  1003.             getch();
  1004.             lastst = closebr;
  1005.             break;
  1006.         case '{':
  1007.             getch();
  1008.             lastst = begin;
  1009.             break;
  1010.         case '}':
  1011.             getch();
  1012.             lastst = end;
  1013.             break;
  1014.         case '?':
  1015.             getch();
  1016.             lastst = hook;
  1017.             break;
  1018.         case '\\':
  1019.             getch();
  1020.             if (lastch == '\n') {
  1021.                 joinch();
  1022.                 goto restart;
  1023.             }
  1024.         default:
  1025.             error(ERR_ILLCHAR, charmsg( lastch ) );
  1026.             getch();
  1027.             goto restart;   /* get a real token */
  1028.         }
  1029.  
  1030.     if (lastst == id)
  1031.         searchkw();
  1032. }
  1033.  
  1034. void
  1035. needpunc(p)
  1036.     enum e_sym      p;
  1037. {
  1038.     if (lastst == p)
  1039.         getsym();
  1040.     else {
  1041.         error(ERR_PUNCT, NULL);
  1042.     }
  1043. }
  1044.